// aes_cryptor.dart
import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
import 'package:pointycastle/block/aes_fast.dart';
import 'package:pointycastle/macs/hmac.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
import 'package:pointycastle/stream/ctr.dart';
import 'dart:math';

class AESCryptor {
  static final BlockCipher _cipher = AESFastEngine();

  static Uint8List _generateIv() {
    final secureRandom = Random.secure();
    final seedData = Uint8List(32);
    for (var i = 0; i < seedData.length; i++) {
      seedData[i] = secureRandom.nextInt(256);
    }

    final random = SecureRandom('Fortuna')..seed(KeyParameter(seedData));
    return random.nextBytes(_cipher.blockSize);
  }

  static Uint8List _pad(Uint8List data) {
    final padLength = 16 - (data.length % 16);
    final paddedData = Uint8List(data.length + padLength)
      ..setRange(0, data.length, data);
    for (var i = data.length; i < paddedData.length; i++) {
      paddedData[i] = padLength;
    }
    return paddedData;
  }

  static Uint8List _unpad(Uint8List data) {
    final padLength = data[data.length - 1];
    return Uint8List.sublistView(data, 0, data.length - padLength);
  }

  static Uint8List deriveKey(String password) {
    final hmac = HMac(SHA256Digest(), 64)
      ..init(KeyParameter(Uint8List.fromList(utf8.encode(password))));
    final key = Uint8List(32);
    hmac.process(Uint8List.fromList([1])); // Can be any constant value.
    hmac.doFinal(key, 0);
    return key;
  }

  Uint8List encrypt(Uint8List data, String password) {
    final key = deriveKey(password);
    final iv = _generateIv();
    final params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
    final encrypter = CTRStreamCipher(_cipher);
    encrypter.init(true, params);

    final paddedData = _pad(data);
    return Uint8List.fromList(iv + encrypter.process(paddedData));
  }

  Uint8List decrypt(Uint8List data, String password) {
    final key = deriveKey(password);
    final iv = Uint8List.sublistView(data, 0, 16);
    final params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
    final decrypter = CTRStreamCipher(_cipher);
    decrypter.init(false, params);

    final decryptedData = decrypter.process(Uint8List.sublistView(data, 16));
    return _unpad(decryptedData);
  }
}
